﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using SiteParser.Core.Logging;
using System.Collections;

namespace SiteParser.Core.ParserEntities
{
	public class ItemTemplateHtmlParser : ParserEntity
	{
		protected string addMethodName = "Add";

		private int startIndex;
		private int maximumIterationCount;
		private int iterationCount;

		public int StartIndex {
			get { return startIndex; }
			set { startIndex = value; }
		}

		public int MaximumIterationCount {
			get { return maximumIterationCount; }
			set { maximumIterationCount = value; }
		}

		#region Private methods

		private bool NextIteration() {
			if (maximumIterationCount != 0) {
				iterationCount++;

				return iterationCount <= maximumIterationCount;
			}

			return true;
		}

		private void Shift(IHtmlIterator htmlIterator) {
			for (int i = 0; i < startIndex && htmlIterator.MoveNext(); i++) { }
		}

		#endregion Private methods

		protected override void ProcessCurrentContext(ParsingContext context, IHtmlIterator htmlIterator) {
			Logger.Info("Processing current context for 'ItemTemplateHtmlParser'");

			var list = context.InnerEntity;
			var itemParser = ChildEntities[0];

			Shift(htmlIterator);

			while (htmlIterator.MoveNext() && NextIteration()) {
				Logger.Info("Processing the next template item");
				var listItem = list is ICollection ? CreateTemplateItem(list) : list;

				ParsingContext itemContext = new ParsingContext() {
					InnerEntity = listItem,
					InnerHtml = htmlIterator.SelectedValue,
					CurrentUrl = context.CurrentUrl,
					ParentContext = context
				};

				itemParser.Parse(itemContext);

				if (list is ICollection) {
					AddTemplateItemToList(list, itemContext.InnerEntity);
				}
			}
		}

		protected virtual void AddTemplateItemToList(object list, object templateItem) {
			if (list == null) {
				throw new ArgumentNullException("list");
			}
			if (templateItem == null) {
				throw new ArgumentNullException("templateItem");
			}

			Type listType = list.GetType();
			var addMethodInfo = listType.GetMethod(addMethodName);

			if (addMethodInfo == null) {
				throw new NotSupportedException(string.Format("Collection should have '{0}' method to add elements", addMethodName));
			}

			addMethodInfo.Invoke(list, new object[] { templateItem });
		}

		protected virtual object CreateTemplateItem(object list) {
			if (list == null) {
				throw new ArgumentNullException("list");
			}

			Type listType = list.GetType();
			Type genericParameterType = listType.GetGenericArguments()[0];
			ConstructorInfo listItemConstructoInfo = genericParameterType.GetConstructor(new Type[0]);
			var listItem = listItemConstructoInfo != null ? listItemConstructoInfo.Invoke(null) : new object();

			return listItem;
		}
	}
}
